/*
 * Copyright Iain Sproat, 2008
 * 
 *
 */
using System;

namespace FreeBase.Fluent
{
	/// <summary>
	/// Description of FBInnerQuery.
	/// </summary>
	public class FBInnerQuery : FBInstruction
	{
		private FBQuery _parentQuery = null;
		private FBQuery _nestedQuery = null;
		private NumberOfRecords _numberOfExpectedRecords = NumberOfRecords.Undefined;
		
		public FBInnerQuery( FBQuery callingQuery )
		{
			if( callingQuery == null )
				throw new ArgumentNullException( "callingQuery" );
			this._parentQuery = callingQuery;
		}
		
		#region Fluent Methods
		public FBInnerQuery Property( string propertyName )
		{
			if( string.IsNullOrEmpty( propertyName ) )
				throw new ArgumentNullException( "propertyName" );
			this.PropertyName = propertyName.ToLower();
			return this;
		}
		
		public FBInnerQuery Many(string propertyName)
		{
			this.Property( propertyName );
			this._numberOfExpectedRecords = NumberOfRecords.Many;
			return this;
		}
		
		public FBInnerQuery One(string propertyName)
		{
			this.Property( propertyName );
			this._numberOfExpectedRecords = NumberOfRecords.One;
			return this;
		}
		
		public FBInnerQuery Which
		{
			get{
				if( string.IsNullOrEmpty(this.PropertyName) )
					throw new ArgumentNullException( "The property name has not yet been set. Please call Expect.One( x ) or Expect.Many(x) first, before callin Which");
				return this;
			}
		}
		
		/// <summary>
		/// This is exactly the same as Meets(), but is here to allow to allow for more fluency to the method calling
		/// </summary>
		/// <param name="innerQuery"></param>
		/// <returns></returns>
		public FBQuery Meet( FBQuery innerQuery )
		{
			return this.Meets( innerQuery );
		}
		
		public FBQuery Meets( FBQuery innerQuery )
		{
			if( string.IsNullOrEmpty( this.PropertyName ) )
				throw new ApplicationException( "The Property name has Not yet been set.Please call Expect.One( x ) or Expect.Many(x) first, before callin Meets(y)" );
			if( innerQuery == null )
				throw new ArgumentNullException( "innerQuery" );
			
			this._nestedQuery = innerQuery;
			return this._parentQuery;
		}
		#endregion
		
		#region Internal Methods for directly accessing internal variables
		
		internal NumberOfRecords NumberOfExpectedRecordsFromInnerQuery
		{
			get{ return this._numberOfExpectedRecords; }
		}
		
		internal FBQuery InnerQuery
		{
			get{ return this._nestedQuery; }
		}
		
		#endregion
	}
}
